{# The one table macro. A page declares columns and hands over rows; it
never writes a
by hand.
{% from "components/macros/table.html" import data_table %}
{{ data_table(columns, rows, empty="No transactions yet") }}
``columns``: list of ``{"key", "label", "kind", "align", "signed"}``.
``kind`` is ``text`` (default), ``money`` (minor units, honours the
row's ``currency`` when it has one; ``signed`` adds a leading ``+`` and
colours by sign, ``toned`` colours by sign without the plus), ``date``,
``int`` or ``status`` (the value is
``{"label", "tone"}``, rendered as a ``badge``); ``align`` is ``left``
(default) or ``right``. Rows are objects or dicts; a blank value
renders as a dash. Zero rows render ``empty_state`` instead.
``row_id`` names each ``
`` (``row_id ~ "-" ~ row.id``) so an action
can swap one row back; a ``{% call(row) data_table(...) %}`` block adds
an actions column rendered per row. #}
{% from "components/macros/feedback.html" import empty_state %}
{% from "components/macros/layout.html" import badge %}
{% macro _cell(row, col) -%}
{%- set value = row[col.key] if row is mapping else row|attr(col.key) -%}
{%- if value is none or value == "" -%}
-
{%- elif col.kind == "money" -%}
{%- set currency = (row["currency"] if row is mapping and "currency" in row else row|attr("currency")) -%}
{{ "+" if col.signed and value > 0 }}{{ value|money(currency if currency is string else "USD") }}
{%- elif col.kind == "status" -%}
{{ badge(value.label, value.tone) }}
{%- elif col.kind == "date" -%}
{{ value|short_date }}
{%- elif col.kind == "int" -%}
{{ "{:,}".format(value) }}
{%- else -%}
{{ value }}
{%- endif -%}
{%- endmacro %}
{# The text colour of one cell: signed money reads by sign. #}
{% macro _tone(row, col) -%}
{%- set value = row[col.key] if row is mapping else row|attr(col.key) -%}
{%- if col.kind == "money" and (col.signed or col.toned) and value is number and value != 0 -%}
{{ "text-aegis-teal" if value > 0 else "text-error" }}
{%- else -%}
text-aegis-text
{%- endif -%}
{%- endmacro %}
{# One row. ``id`` lets an action swap this row back by itself; ``oob``
marks it as an out-of-band answer (pattern 2); ``actions`` is a macro
(a call block's ``caller``) rendering the trailing actions cell. #}
{% macro table_row(columns, row, id=None, oob=False, actions=None) %}
{# A row swapped out of band travels wrapped: a bare
at the top
of a response bound for anything but a table is thrown away by the
HTML parser, and its cells spill into whatever was being swapped — a
stray row loose in a dialog. htmx unwraps a template before it swaps,
so this is the way to send one anywhere. #}
{% if oob %}{% endif %}
{% for col in columns %}
{{ _cell(row, col) }}
{% endfor %}
{% if actions %}
{{ actions(row) }}
{% endif %}
{% if oob %}{% endif %}
{% endmacro %}
{% macro data_table(columns, rows, empty="Nothing here yet", row_id=None) %}
{% if rows %}
{% for col in columns %}
{{ col.label }}
{% endfor %}
{% if caller is defined %}
Actions
{% endif %}
{% for row in rows %}
{{ table_row(columns, row, id=(row_id ~ "-" ~ (row["id"] if row is mapping else row.id)) if row_id else None, actions=caller if caller is defined else None) }}
{% endfor %}
{% else %}
{{ empty_state(empty) }}
{% endif %}
{% endmacro %}
{# Page navigation for a listed table. ``pager`` is the route's
``{start, end, total, prev, next}`` (``None`` when one page); the links
re-request the same URL and swap ``target`` in place. #}
{% macro pager(pager, target) %}
{% if pager %}
{% endif %}
{% endmacro %}